package concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by sunzhengjie on 2017/1/19.
 */
public class Restaurant {
    Meal meal;
    ExecutorService  exec = Executors.newCachedThreadPool();
    final Chef chef = new Chef(this);
    final WaitPerson waitPerson = new WaitPerson(this);//如果不是final引用的对象可能被改变，不同线程获取waitPerson对象锁可能不同。
    public Restaurant() {
        exec.execute(chef);
        exec.execute(waitPerson);
    }

    public static class Meal {
        private final int orderNum;
        public Meal(int orderNum){
            this.orderNum = orderNum;
        }
        public String toString(){
            return "Meal " + orderNum;
        }
    }

    public static class Chef implements Runnable{
        Restaurant restaurant;
        int count = 0;
        public Chef(Restaurant restaurant) {
            this.restaurant = restaurant;
        }

        @Override
        public void run() {
            try{
                while(!Thread.interrupted()){
                    synchronized (this){
                        while(restaurant.meal != null){
                            wait();
                        }
                    }
                    if(++count == 10){
                        System.out.println("restaurant closing");
                        restaurant.exec.shutdownNow();
                    }
                    synchronized (restaurant.waitPerson){
                    restaurant.meal = new Meal(count);
                        restaurant.waitPerson.notifyAll();
                    }
                    System.out.println("order up");
                    TimeUnit.SECONDS.sleep(1);
                }
            }catch (InterruptedException ex){
                System.out.println("Chef interrupt");
            }
        }
    }

    public static class WaitPerson implements Runnable{
        Restaurant restaurant;

        public WaitPerson(Restaurant restaurant) {
            this.restaurant = restaurant;
        }

        @Override
        public void run() {
            try{
                while(!Thread.interrupted()){
                    synchronized (this){
                        while(restaurant.meal == null){
                            wait();
                        }
                    }
                    System.out.println("WaitPerson got " + restaurant.meal);
                    synchronized (restaurant.chef){
                    restaurant.meal = null;
                        restaurant.chef.notifyAll();
                    }
                }
            }catch (InterruptedException ex){
                System.out.println("WaitPerson interrupt");
            }
        }
    }

    public static void main(String[] arg0) {
        new Restaurant();
    }
}
